import {TokenKind, Token, Tokenizer} from './nscanner';
import {Statement, Prog, FunctionCall, FunctionDecl, FunctionBody} from './nast';

////////////////////////////////////////////////////////////////////////////////
//Parser

/**
 * 语法解析器。
 * 通常用parseProg()作为入口，解析整个程序。也可以用下级的某个节点作为入口，只解析一部分语法。
 */
export class Parser{
    tokenizer:Tokenizer;

    constructor(tokenizer:Tokenizer){
        this.tokenizer = tokenizer;
    }

    /**
     * 解析Prog
     * 语法规则：
     * prog = (functionDecl | functionCall)* ;
     */
    parseProg():Prog{
        let stmts: Statement[] = [];
        let stmt: Statement|null = null;
        let token = this.tokenizer.peek();

        //每次循环解析一个语句
        while(token != undefined && token.kind != TokenKind.EOF){
	        if (token.kind == TokenKind.Keyword && token.text =='function'){
	            //先尝试一下函数声明
                stmt = this.parseFunctionDecl();
		
            }
            else if (token.kind == TokenKind.Identifier){
                //再尝试一下函数调用
                stmt = this.parseFunctionCall();
	        }
	    
            if (stmt != null && stmt != undefined){
                //读取成功压入stmts
                stmts.push(stmt);
                console.log("parseFunctionDecl or parseFunctionCall successed!");
            }
            else {
                //读取失败
	            console.log("neither parseFunctionDecl nor parseFunctionCall!!!");
            }
        
            //下一个token
	        token = this.tokenizer.peek();
        }

        return new Prog(stmts);
    }

    /**
     * 解析函数声明
     * 语法规则：
     * functionDecl: "function" Identifier "(" ")"  functionBody;
     */
    parseFunctionDecl():FunctionDecl|null{
        let oldPos:number = this.tokenizer.position();
        let t:Token = this.tokenizer.next();

        if (t.kind == TokenKind.Keyword && t.text == "function"){
            t = this.tokenizer.next();
            if (t.kind == TokenKind.Identifier){
                //读取"("和")"
                let t1 = this.tokenizer.next();
                if (t1.text=="("){
                    let t2 = this.tokenizer.next();
                    if (t2.text==")"){
                        //尝试读取FunctionBody
                        let functionBody = this.parseFunctionBody();
                        if (FunctionBody.isFunctionBodyNode(functionBody)){
                            console.log("parseFunctionBody successed!");

                            //如果解析成功，从这里返回
                            return new FunctionDecl(t.text, functionBody);
                        }
                        else{
                            console.log("Error parsing FunctionBody in FunctionDecl");
                            return null;
                        }
                    }
                    else{
                        //括号不匹配
                        console.log("Expecting ')' in FunctionDecl, while we got a " + t.text);
                        return null;
                    }
                }
                else{
                    //函数声明格式不正确
                    console.log("Expecting '(' in FunctionDecl, while we got a " + t.text);
                    return null;
                }
            }
        }

        //如果解析不成功，回溯，返回null。
        this.tokenizer.traceBack(oldPos);
        return null;
    }

    /**
     * 解析函数体
     * 语法规则：
     * functionBody : '{' functionCall* '}' ;
     */
    parseFunctionBody():FunctionBody|null{
        let oldPos:number = this.tokenizer.position();
        let stmts:FunctionCall[] = [];
        let t:Token = this.tokenizer.next();

        if(t.text == "{"){
            //从函数中读取一个个的FunctionCall
            let functionCall = this.parseFunctionCall();
            while(FunctionCall.isFunctionCallNode(functionCall)){  //解析函数体
                stmts.push(functionCall);
                functionCall = this.parseFunctionCall();
            }

            t = this.tokenizer.next();
            if (t.text == "}"){
                //FunctionBody读取结束
                return new FunctionBody(stmts);
            }
            else{
                //花括号不匹配
                console.log("Expecting '}' in FunctionBody, while we got a " + t.text);
                return null;
            }
        }
        else{
            //FunctionBody格式错误
            console.log("Expecting '{' in FunctionBody, while we got a " + t.text);
            return null;
        }

        //如果解析不成功，回溯，返回null。
        this.tokenizer.traceBack(oldPos);
        return null;
    }

    /**
     * 解析函数调用
     * 语法规则：
     * functionCall : Identifier '(' parameterList? ')' ;
     * parameterList : StringLiteral (',' StringLiteral)* ;
     */
    parseFunctionCall():FunctionCall|null{
        let oldPos:number = this.tokenizer.position();
        let params:string[] = [];
        let t:Token = this.tokenizer.next();

        if(t.kind == TokenKind.Identifier){
            let t1:Token = this.tokenizer.next();
            if (t1.text == "("){
                let t2:Token = this.tokenizer.next();
                //循环，读出所有参数
                while(t2.text != ")"){
                    if (t2.kind == TokenKind.StringLiteral){
                        //字符串参数
                        params.push(t2.text);
                    }
                    else{
                        //暂不支持其他类型参数
                        console.log("Expecting parameter in FunctionCall, while we got a " + t2.text);
                        return null;  //出错时，就不在错误处回溯了。
                    }

                    t2 = this.tokenizer.next();
                    //参数部分未结束，分析其他参数
                    if (t2.text != ")"){
                        if (t2.text == ","){
                            //其他参数
                            t2 = this.tokenizer.next();
                        }
                        else{
                            //格式错误
                            console.log("Expecting a comma in FunctionCall, while we got a " + t2.text);
                            return null;
                        }
                    }
                }

                //参数获取完毕
                t2 = this.tokenizer.next();
                if (t2.text == ";"){
                    //消化掉一个分号：;
                    console.log("parseFunctionCall successed!");
                    return new FunctionCall(t.text, params);
                }
                else{
                    //格式错误
                    console.log("Expecting a semicolon in FunctionCall, while we got a " + t2.text);
                    return null;
                }
            }
        }

        //如果解析不成功，回溯，返回null。
        this.tokenizer.traceBack(oldPos);
        return null;
    }
}
